home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Format 1995 June
/
MacFormat 25.iso
/
Shareware City
/
Developers
/
OutOfPhase1.1 Source
/
OutOfPhase Folder
/
FrameObject.c
< prev
next >
Wrap
Text File
|
1994-08-15
|
14KB
|
465 lines
/* FrameObject.c */
/*****************************************************************************/
/* */
/* Out Of Phase: Digital Music Synthesis on General Purpose Computers */
/* Copyright (C) 1994 Thomas R. Lawrence */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 2 of the License, or */
/* (at your option) any later version. */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program; if not, write to the Free Software */
/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* */
/* Thomas R. Lawrence can be reached at tomlaw@world.std.com. */
/* */
/*****************************************************************************/
#include "MiscInfo.h"
#include "Audit.h"
#include "Debug.h"
#include "Definitions.h"
#include "FrameObject.h"
#include "NoteObject.h"
#include "Memory.h"
#include "DataMunging.h"
#include "NoteImages.h"
#include "Frequency.h"
#include "StaffCalibration.h"
#include "Fractions.h"
struct FrameObjectRec
{
NoteObjectRec** NoteArray; /* too much overhead to use ArrayRec object */
OrdType Width; /* cached width value; 0 == unknown */
};
/* allocate a new frame. */
FrameObjectRec* NewFrame(void)
{
FrameObjectRec* Frame;
Frame = (FrameObjectRec*)AllocPtrCanFail(sizeof(FrameObjectRec),"FrameObjectRec");
if (Frame == NIL)
{
FailurePoint1:
return NIL;
}
Frame->NoteArray = (NoteObjectRec**)AllocPtrCanFail(0,"FrameNoteObjectArray");
if (Frame->NoteArray == NIL)
{
FailurePoint2:
ReleasePtr((char*)Frame);
goto FailurePoint1;
}
Frame->Width = 0;
return Frame;
}
/* dispose of a frame and all notes it contains. be careful here since this won't */
/* worry about tie references to notes contained in the frame. */
void DisposeFrameAndContents(FrameObjectRec* Frame)
{
long Scan;
Scan = NumNotesInFrame(Frame) - 1;
while (Scan >= 0)
{
DisposeNote(Frame->NoteArray[Scan]);
Scan -= 1;
}
ReleasePtr((char*)(Frame->NoteArray));
ReleasePtr((char*)Frame);
}
/* get the number of notes contained in the frame */
long NumNotesInFrame(FrameObjectRec* Frame)
{
CheckPtrExistence(Frame);
return PtrSize((char*)(Frame->NoteArray)) / sizeof(NoteObjectRec*);
}
/* get the note specified by the index from the frame object */
struct NoteObjectRec* GetNoteFromFrame(FrameObjectRec* Frame, long Index)
{
CheckPtrExistence(Frame);
PRNGCHK(Frame->NoteArray,&(Frame->NoteArray[Index]),sizeof(NoteObjectRec*));
return Frame->NoteArray[Index];
}
/* delete a note in the frame. returns True if successful. */
MyBoolean DeleteNoteFromFrame(FrameObjectRec* Frame, long Index)
{
NoteObjectRec** NewArray;
CheckPtrExistence(Frame);
NewArray = (NoteObjectRec**)RemoveEntryFromArrayCopy((char*)(Frame->NoteArray),
Index,sizeof(NoteObjectRec*));
if (NewArray != NIL)
{
ReleasePtr((char*)(Frame->NoteArray));
Frame->NoteArray = NewArray;
Frame->Width = 0;
return True;
}
else
{
return False;
}
}
/* append a note to the frame. returns True if successful. */
MyBoolean AppendNoteToFrame(FrameObjectRec* Frame, struct NoteObjectRec* Note)
{
NoteObjectRec** NewRef;
long OldSize;
CheckPtrExistence(Frame);
CheckPtrExistence(Note);
OldSize = PtrSize((char*)(Frame->NoteArray));
ERROR(IsThisACommandFrame(Frame),PRERR(ForceAbort,
"AppendNoteToFrame: adding note to command frame"));
ERROR(!IsThisACommandFrame(Frame) && (NumNotesInFrame(Frame) > 0)
&& IsItACommand(Note),PRERR(ForceAbort,
"AppendNoteToFrame: adding command to note frame"));
NewRef = (NoteObjectRec**)ResizePtr((char*)(Frame->NoteArray),
OldSize + sizeof(NoteObjectRec*));
if (NewRef == NIL)
{
return False;
}
Frame->NoteArray = NewRef;
Frame->NoteArray[OldSize / sizeof(NoteObjectRec*)] = Note;
Frame->Width = 0;
return True;
}
/* find out if this is a command frame. command frames are allowed to have a */
/* single command and nothing else in them */
MyBoolean IsThisACommandFrame(FrameObjectRec* Frame)
{
CheckPtrExistence(Frame);
return (NumNotesInFrame(Frame) == 1) && IsItACommand(Frame->NoteArray[0]);
}
/* find out the width of this command/note frame and draw it if the flag is set. */
/* it assumes the clipping rectangle is set up properly. the X and Y parameters */
/* specify the left edge of the note and the Middle C line. */
/* this routine does not handle drawing of ties. */
OrdType WidthOfFrameAndDraw(WinType* Window, OrdType X, OrdType Y,
FontType Font, FontSizeType FontSize, OrdType FontHeight,
FrameObjectRec* Frame, MyBoolean ActuallyDraw,
MyBoolean GreyedOut)
{
OrdType Width;
/* this caching of the width of the frame should speed things up */
if ((Frame->Width != 0) && !ActuallyDraw)
{
/* we can only do this if we aren't drawing! */
return Frame->Width;
}
/* we should be able to find ways of overlapping the notes if they won't */
/* be on top of each other on screen but we're not going to for now. */
if (IsThisACommandFrame(Frame))
{
/* it's a command frame, so draw using the special command drawing routines */
Width = DrawCommandOnScreen(Window,X,Y,Font,FontSize,FontHeight,
GetNoteFromFrame(Frame,0),ActuallyDraw,GreyedOut);
}
else
{
long Limit;
long Scan;
/* we have to draw the notes ourselves. */
X -= LEFTNOTEEDGEINSET;
Width = 0;
Limit = NumNotesInFrame(Frame);
for (Scan = 0; Scan < Limit; Scan += 1)
{
NoteObjectRec* Note;
/* get the note to be drawn */
Note = GetNoteFromFrame(Frame,Scan);
CheckPtrExistence(Note);
/* do the icon stuff */
if (ActuallyDraw)
{
Bitmap* Image;
Bitmap* Mask;
OrdType NoteOffset;
/* first, obtain the proper image for the duration */
if (!GetNoteIsItARest(Note))
{
switch (GetNoteDuration(Note))
{
default:
EXECUTE(PRERR(ForceAbort,
"LengthOfCommandFrameAndDraw: bad duration value"));
break;
case e64thNote:
Image = SixtyFourthNoteImage;
Mask = SixtyFourthNoteMask;
break;
case e32ndNote:
Image = ThirtySecondNoteImage;
Mask = ThirtySecondNoteMask;
break;
case e16thNote:
Image = SixteenthNoteImage;
Mask = SixteenthNoteMask;
break;
case e8thNote:
Image = EighthNoteImage;
Mask = EighthNoteMask;
break;
case e4thNote:
Image = QuarterNoteImage;
Mask = QuarterNoteMask;
break;
case e2ndNote:
Image = HalfNoteImage;
Mask = HalfNoteMask;
break;
case eWholeNote:
Image = WholeNoteImage;
Mask = WholeNoteMask;
break;
case eDoubleNote:
Image = DoubleNoteImage;
Mask = DoubleNoteMask;
break;
case eQuadNote:
Image = QuadNoteImage;
Mask = QuadNoteMask;
break;
}
}
else
{
switch (GetNoteDuration(Note))
{
default:
EXECUTE(PRERR(ForceAbort,
"LengthOfCommandFrameAndDraw: bad duration value"));
break;
case e64thNote:
Image = SixtyFourthRestImage;
Mask = SixtyFourthRestMask;
break;
case e32ndNote:
Image = ThirtySecondRestImage;
Mask = ThirtySecondRestMask;
break;
case e16thNote:
Image = SixteenthRestImage;
Mask = SixteenthRestMask;
break;
case e8thNote:
Image = EighthRestImage;
Mask = EighthRestMask;
break;
case e4thNote:
Image = QuarterRestImage;
Mask = QuarterRestMask;
break;
case e2ndNote:
Image = HalfRestImage;
Mask = HalfRestMask;
break;
case eWholeNote:
Image = WholeRestImage;
Mask = WholeRestMask;
break;
case eDoubleNote:
Image = DoubleRestImage;
Mask = DoubleRestMask;
break;
case eQuadNote:
Image = QuadRestImage;
Mask = QuadRestMask;
break;
}
}
/* duplicate images so we can modify them */
Image = DuplicateBitmap(Image);
if (Image == NIL)
{
goto FailurePoint;
}
Mask = DuplicateBitmap(Mask);
if (Mask == NIL)
{
DisposeBitmap(Image);
goto FailurePoint;
}
/* now, handle divisions */
switch (GetNoteDurationDivision(Note))
{
default:
EXECUTE(PRERR(ForceAbort,
"LengthOfCommandFrameAndDraw: bad division value"));
break;
case eDiv1Modifier:
/* no change */
break;
case eDiv3Modifier:
BitmapOrIntoBitmap(Div3Image,Image);
BitmapOrIntoBitmap(Div3Mask,Mask);
break;
case eDiv5Modifier:
BitmapOrIntoBitmap(Div5Image,Image);
BitmapOrIntoBitmap(Div5Mask,Mask);
break;
case eDiv7Modifier:
BitmapOrIntoBitmap(Div7Image,Image);
BitmapOrIntoBitmap(Div7Mask,Mask);
break;
}
/* handle dots */
if (GetNoteDotStatus(Note))
{
BitmapOrIntoBitmap(DotImage,Image);
BitmapOrIntoBitmap(DotMask,Mask);
}
/* sharps and flats require more clever handling */
if ((GetNoteFlatOrSharpStatus(Note) & eSharpModifier) != 0)
{
BitmapOrIntoBitmap(SharpImage,Image);
BitmapOrIntoBitmap(SharpMask,Mask);
}
if ((GetNoteFlatOrSharpStatus(Note) & eFlatModifier) != 0)
{
BitmapOrIntoBitmap(FlatImage,Image);
BitmapOrIntoBitmap(FlatMask,Mask);
}
/* check greying status */
if (GreyedOut)
{
BitmapAndIntoBitmap(GreyMask,Image);
}
/* perform the drawing */
NoteOffset = Y + ConvertPitchToPixel(GetNotePitch(Note),
GetNoteFlatOrSharpStatus(Note))
- TOPNOTESTAFFINTERSECT - GetCenterNotePixel();
BicBitmap(Window,X,NoteOffset,Mask);
OrBitmap(Window,X,NoteOffset,Image);
/* dump the bitmaps */
DisposeBitmap(Mask);
DisposeBitmap(Image);
/* increment X for the next time around */
X += INTERNALSEPARATION;
}
/* update the width count */
FailurePoint:
if (Width == 0)
{
/* first time you get the whole width */
Width = ICONWIDTH - LEFTNOTEEDGEINSET;
}
else
{
/* other times, you just get whatever extra there is */
Width += INTERNALSEPARATION;
}
}
}
Frame->Width = Width;
return Width;
}
/* find out the duration of the specified frame. returns the duration of the */
/* frame as a fraction */
void DurationOfFrame(FrameObjectRec* Frame, struct FractionRec* Frac)
{
long Scan;
long Limit;
NoteObjectRec* Note;
CheckPtrExistence(Frame);
if (IsThisACommandFrame(Frame))
{
Frac->Integer = 0;
Frac->Fraction = 0;
Frac->Denominator = (64*3*5*7*2);
return;
}
Limit = NumNotesInFrame(Frame);
ERROR(Limit < 1,PRERR(ForceAbort,"DurationOfFrame called on empty frame"));
/* obtain duration of first element */
Note = GetNoteFromFrame(Frame,0);
GetNoteDurationFrac(Note,Frac);
for (Scan = 0; Scan < Limit; Scan += 1)
{
FractionRec TempFrac;
Note = GetNoteFromFrame(Frame,Scan);
GetNoteDurationFrac(Note,&TempFrac);
if (FracGreaterThan(Frac,&TempFrac))
{
/* choose smallest one */
*Frac = TempFrac;
}
}
}
/* make a total (deep) copy of the frame and the notes it contains */
FrameObjectRec* DeepDuplicateFrame(FrameObjectRec* Frame)
{
FrameObjectRec* Copy;
long Limit;
long Scan;
CheckPtrExistence(Frame);
Copy = NewFrame();
if (Copy == NIL)
{
FailurePoint1:
return NIL;
}
Limit = NumNotesInFrame(Frame);
for (Scan = 0; Scan < Limit; Scan += 1)
{
NoteObjectRec* NoteCopy;
NoteCopy = DeepCopyNoteObject(GetNoteFromFrame(Frame,Scan));
if (NoteCopy == NIL)
{
FailurePoint2:
DisposeFrameAndContents(Copy);
goto FailurePoint1;
}
if (!AppendNoteToFrame(Copy,NoteCopy))
{
FailurePoint2a:
DisposeNote(NoteCopy);
goto FailurePoint2;
}
}
return Copy;
}